# coding: utf-8
'''
Created on May 25, 2010

@author: guard
'''
import codecs
from xml.etree.ElementTree import ElementTree
import re
import json

class Team(object):
    def __init__(self, id, num, name, city=None, captain=None):
        self.id = id
        self.num = num
        self.name = name
        self.city = city
        self.captain = captain
        
    def update_from_dict(self, **kwargs):
        for attr in ('num', 'name', 'city', 'captain'):
            if attr in kwargs:
                setattr(self, attr, kwargs[attr])
            
    def update(self, team):
        for attr in ('num', 'name', 'city', 'captain'):
            setattr(self, attr, getattr(team, attr))

class Game(object):
    def __init__(self, questions_number, title=None, date=None, teams=[], results=None, groups=[], teams_to_groups={}):
        '''
        Constructor
        '''
        self.title = title
        self.date = date
        self.teams = {}
        self.results = {}
        self.questions_number = questions_number
        for team in teams:
            self._add_team(team, results.get(team.id, None) if results is not None else None)
        self.groups = groups
        self.teams_to_groups = teams_to_groups
        if groups and not teams_to_groups:
            for n in groups:
                self.teams_to_groups[n] = []         
        self.__extra_data = {}
    
    def _add_team(self, team, results=None, group=0):
        self.teams[team.id] = team
        if results is None:
            self.results[team.id] = [False] * self.questions_number
        else:
            if len(results) < self.questions_number:
                results += [False] * (self.questions_number - len(results))
#            elif len(results) < self.questions_number:
#                results = results[:self.questions_number]
            self.results[team.id] = results         
            
    def setExtraData(self, key, val, persistent=True):
        self.__extra_data[key] = (val, persistent)
        
    def extraData(self, key):
        return self.__extra_data.get(key, (None, True))
    
    def hasExtraKey(self, key):
        return key in self.__extra_data
    
    def update_teams(self, teams, results=None):
        for team in teams:
            if team.id in self.teams:
                self.teams[team.id].update(team)
            else:
                self._add_team(team, results if (results is not None and team.id in results) else None)
        d = [team.id for team in teams]
        tids = [team_id for team_id in self.teams if team_id not in d]
        for team_id in tids:
            self.remove_team(team_id)
            
    def update_groups(self, groups):
        t2g = {}
        g = {}
        for n in groups:
            t2g[n] = self.teams_to_groups.get(groups[n][1], [])
            g[n] = groups[n][0]
        self.groups = g
        self.teams_to_groups = t2g
            
    def remove_team(self, team_id):
        del self.teams[team_id]
            
    def result(self, team_id, question_number):
        return self.results[team_id][question_number]
    
    def setResult(self, team_id, question_number, value):
        self.results[team_id][question_number] = value
        
    def total(self, team_id, left=0, right=None):
        if right is None:
            right = self.questions_number-1
        return sum(self.results[team_id][left:right+1])
    
    def set_questions_number(self, n):
        if n > self.questions_number:
            for team_id in self.results:
                self.results[team_id] += [False] * (n - len(self.results[team_id]))
        self.questions_number = n
    
    @staticmethod
    def from_file(filename):
        teams = []
        results = {}
        groups = {}
        et = ElementTree()
        et.parse(filename)
        root = et.getroot()
        questions_number = int(root.attrib['questionsNumber'])
        game_title = root.attrib['title']
        game_date = root.attrib['date']
        
        for group in root.find('groups').getiterator('group'):
            groups[int(group.attrib['number'])] = group.attrib['name']
        t2g = {0: []}
        for gnum in groups:
            t2g[gnum] = []
    
        for team in root.find('teams').getiterator('team'):
            r = [False] * questions_number
            t_num = int(team.attrib['number'])
            t_group = int(team.attrib['group'])
            if '_id' in team.attrib:
                t_id = int(team.attrib['_id'])
            else:
                t_id = None
            t_name, t_city, t_captain = [team.attrib[s] for s
                                         in ('name', 'city', 'captain')] 
            t_quests = team.find('questionNumbers').text
            if t_quests:
                for i in re.split(r',\s*', t_quests):
                    r[int(i)-1] = True
            tt = Team(t_id, t_num, t_name, t_city, t_captain)
            teams.append((tt, r))
            t2g[t_group].append(tt)
        teams.sort(key=lambda x: x[0].num)
        i = max([-1] + [x[0].id for x in teams if x[0].id is not None])
        for x in teams:
            if x[0].id is None:
                i += 1
                x[0].id = i
        for n in t2g:
            t2g[n] = [tt.id for tt in t2g[n]]
        for i in range(len(teams)):
            t = teams[i]
            results[t[0].id] = t[1] 
            teams[i] = t[0]
        g = Game(questions_number, game_title, game_date, teams, results, groups, t2g)
        
        extra_data = root.find('extra-data')
        if extra_data is not None:
            for entry in extra_data.getiterator('entry'):
                try:
                    key = entry.attrib['key']
                    data = json.loads(entry.text)
                    g.setExtraData(key, data)
                except Exception as e:
                    warn(u'Ошибка загрузки данных: {0}'.format(e))
                    continue        

        return g
    
    def to_file(self, filename):
        s = []
        s.append(u'<?xml version="1.0" encoding="Windows-1251"?>')
        s.append(u'<gameset title="{0}" date="{1}" questionsNumber="{2}">'.format(self.title, 
                                                                                  self.date,
                                                                                  self.questions_number))
        groups_to_teams = {}
        if self.groups:
            s.append(u'<groups>')
            for n in self.groups:
                s.append(u'<group number="{0}" name="{1}" />'.format(n, self.groups[n]))
                for tid in self.teams_to_groups[n]:
                    groups_to_teams[tid] = n
            s.append(u'</groups>')
        else:
            s.append(u'<groups />')
            
        s.append(u'<teams>')
        for tid, t in self.teams.items():
            s.append(u'<team _id="{0}" number="{1}" name="{2}" city="{3}" captain="{4}" group="{5}">'.format(
                    tid, t.num, t.name, t.city, t.captain, groups_to_teams.get(tid, 0)))
            s.append(u'<questionNumbers>{0}</questionNumbers>'.format(', '.join(
                    [str(x+1) for x in range(self.questions_number) if self.result(tid, x)])))
            s.append(u'</team>')
        s.append(u'</teams>')
        
        s.append(u'<extra-data>')
        for key, (data, persistent) in self.__extra_data.items():
            if not persistent:
                continue
            s.append('<entry key="{0}"><![CDATA[{1}]]></entry>'.format(key, json.dumps(data)))            
        s.append(u'</extra-data>')
        
        s.append(u'</gameset>')
        f = codecs.open(filename, 'w', 'cp1251')
        f.write(''.join(s))
        f.close()
